﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TDengine.Driver.Client;
using TDengine.Driver;
using System.Collections.Concurrent;
using System.Threading;
using VOL.Entity.VM;
using VOL.Core.Extensions;
using System.Reflection;
using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;

namespace VOL.Core.Utilities
{
    public class TDengineHelper : IDisposable
    {
        private readonly string _connectionString;
        private ITDengineClient _client;

        public TDengineHelper(string ip, int port, string username, string password)
        {
            _connectionString = $"host={ip};port={port};username={username};password={password}";
        }

        public void Connect()
        {
            _client = DbDriver.Open(new ConnectionStringBuilder(_connectionString));
            if (_client == null)
                throw new Exception("Failed to connect to TDengine");
        }

        public long ExecuteNonQuery(string sql)
        {
            try
            {
                return _client.Exec(sql);
            }
            catch (Exception ex)
            {
                throw new Exception($"ExecuteNonQuery failed: {ex.Message}");
            }
        }

        public List<T> Query<T>(string sql, Func<IRows, T> mapper)
        {
            var results = new List<T>();
            using (var reader = _client.Query(sql))
            {
                while (reader.Read())
                {
                    results.Add(mapper(reader));
                }
            }
            return results;
        }

        public long BatchInsert(string tableName, List<Dictionary<string, object>> data)
        {
            var sql = new StringBuilder($"INSERT INTO {tableName} VALUES ");
            foreach (var item in data)
            {
                sql.Append("(");
                foreach (var kv in item)
                {
                    sql.Append($"'{kv.Value}',");
                }
                sql.Length--; // 移除末尾逗号
                sql.Append("),");
            }
            sql.Length--; // 移除末尾逗号

            return ExecuteNonQuery(sql.ToString());
        }

        public void Dispose()
        {
            _client?.Dispose();
        }
    }
    public static class TDengineExtensions
    {
        public static TDengineHelper CreateHelper(
            this string ip,
            int port = 6030,
            string user = "root",
            string pwd = "taosdata")
        {
            return new TDengineHelper(ip, port, user, pwd);
        }
    }


    public class TDenginePoolHelper : IDisposable
    {
        private static readonly ConcurrentDictionary<string, ConnectionPool> _pools =
            new ConcurrentDictionary<string, ConnectionPool>();

        private ITDengineClient _client;
        private readonly string _poolKey;

        private TDenginePoolHelper(string poolKey, ITDengineClient client)
        {

            _poolKey = poolKey;
            _client = client;
        }

        public static TDenginePoolHelper Create(string ip, int port, string username, string password,
            int maxPoolSize = 10, int maxIdleTime = 300)
        {
            var poolKey = $"{ip}:{port}:{username}";

            var pool = _pools.GetOrAdd(poolKey, key =>
                new ConnectionPool(ip, port, username, password, maxPoolSize, maxIdleTime));

            var client = pool.GetConnection();
            return new TDenginePoolHelper(poolKey, client);
        }

        public long ExecuteNonQuery(string sql)
        {
            try
            {
                return _client.Exec(sql);
            }
            catch (Exception ex)
            {
                throw new Exception($"ExecuteNonQuery failed: {ex.Message}");
            }
        }

        public List<T> Query<T>(string sql, Func<IRows, T> mapper)
        {
            var results = new List<T>();
            using (var reader = _client.Query(sql))
            {
                while (reader.Read())
                {
                    results.Add(mapper(reader));
                }
            }
            return results;
        }
        public List<T> Query<T>(string sql) where T : new()
        {
            var results = new List<T>();
            using (var reader = _client.Query(sql))
            {
                var props = typeof(T).GetProperties();
                var columnNames = Enumerable.Range(0, reader.FieldCount)
                                      .Select(reader.GetName)
                                      .ToList();

                while (reader.Read())
                {
                    var item = new T();
                    foreach (var prop in props)
                    {
                        var columnName = GetColumnName(prop).ToLower(); // 处理列名映射
                        //if (columnNames.Contains(columnName) &&
                        //    !string.IsNullOrEmpty(reader.GetValue(reader.GetOrdinal(columnName)).ToString()))
                       
                        if (columnNames.Contains(columnName.ToLower()))
                        {
                            try
                            {
                                var ordinal = reader.GetOrdinal(columnName.ToLower());
                                var ty = reader.GetFieldType(ordinal);
                                var na= reader.GetName(ordinal);
                                var k = reader.GetDataTypeName(ordinal);
                                object value=null;//reader.GetValue(ordinal);// reader[columnName];
                                if (ty.Name == "String" && value is DBNull)
                                    value = null;
                                else if (ty.Name == "DateTime")
                                    value = (DateTime)reader.GetValue(ordinal);
                                else if (ty.Name == "Int64")
                                    value = null;
                                else if (ty.Name == "Int32")
                                    value = null;
                                else if (ty.Name == "Int16")
                                    value = null;
                                else if (ty.Name == "Double")
                                    value = null;
                                else if (ty.Name == "Single")
                                    value = (float)reader.GetValue(ordinal);
                                else if (ty.Name == "Boolean")
                                    value = null;
                                else if (ty.Name == "Float")
                                    value = (float)reader.GetValue(ordinal);
                                else if (ty.Name == "Byte[]")
                                    value = Encoding.UTF8.GetString((byte[])reader.GetValue(ordinal));
                                else if (ty.Name == "Decimal")
                                    value = null;
                                // 处理DBNull值
                                if (value is DBNull)
                                    value = null;
                                // 设置属性值
                                else
                                prop.SetValue(item, Convert.ChangeType(value, prop.PropertyType));
                            }
                            catch { /* 处理转换异常 */ }
                        }
                    }
                    results.Add(item);
                }
            }
            return results;
        }

        private string GetColumnName(PropertyInfo prop)
        {
            // 这里可以添加自定义列名映射逻辑
            return prop.Name;
        }

        public void Dispose()
        {
            if (_client != null && _pools.TryGetValue(_poolKey, out var pool))
            {
                pool.ReturnConnection(_client);
                _client = null;
            }
        }

        // 内部连接池实现
        private class ConnectionPool
        {
            private readonly string _connectionString;
            private readonly int _maxPoolSize;
            private readonly int _maxIdleSeconds;
            private readonly ConcurrentQueue<ITDengineClient> _idleConnections = new ConcurrentQueue<ITDengineClient>();
            private int _activeConnections;
            private Timer _cleanupTimer;

            public ConnectionPool(string ip, int port, string username, string password,
                int maxPoolSize, int maxIdleSeconds)
            {
                _connectionString = $"host={ip};port={port};username={username};password={password}";
                _maxPoolSize = maxPoolSize;
                _maxIdleSeconds = maxIdleSeconds;

                // 启动定时清理空闲连接
                _cleanupTimer = new Timer(CleanupIdleConnections, null,
                    TimeSpan.FromMinutes(1),
                    TimeSpan.FromMinutes(1));
            }

            public ITDengineClient GetConnection()
            {
                lock (_idleConnections)
                {
                    // 尝试从空闲队列获取连接
                    if (_idleConnections.TryDequeue(out ITDengineClient idleClient))
                    {
                        _activeConnections++;
                        return idleClient;
                    }

                    // 创建新连接
                    if (_activeConnections < _maxPoolSize)
                    {
                        var newClient = CreateNewConnection();
                        _activeConnections++;
                        return newClient;
                    }

                    throw new Exception("Connection pool limit reached");
                }
            }

            public void ReturnConnection(ITDengineClient client)
            {
                lock (_idleConnections)
                {
                    _activeConnections--;
                    client.SetLastUsed();
                    _idleConnections.Enqueue(client);
                }
            }

            private ITDengineClient CreateNewConnection()
            {
                var client = DbDriver.Open(new ConnectionStringBuilder(_connectionString));
                if (client == null)
                    throw new Exception("Failed to connect to TDengine");

                client.GetLastUsed();
                return client;
            }

            private void CleanupIdleConnections(object state)
            {
                lock (_idleConnections)
                {
                    int initialCount = _idleConnections.Count;
                    for (int i = 0; i < initialCount; i++)
                    {
                        if (_idleConnections.TryDequeue(out ITDengineClient client))
                        {
                            if ((DateTime.UtcNow - client.GetLastUsed()).TotalSeconds > _maxIdleSeconds)
                            {
                                client.Dispose(); // 关闭空闲过久的连接
                            }
                            else
                            {
                                _idleConnections.Enqueue(client); // 放回队列
                            }
                        }
                    }
                }
            }

            public void Dispose()
            {
                _cleanupTimer?.Dispose();

                while (_idleConnections.TryDequeue(out ITDengineClient client))
                {
                    client.Dispose();
                }
            }
        }
    }

    // 扩展方法为 ITDengineClient 添加时间戳追踪
    public static class ITDengineClientExtensions
    {
        public static DateTime LastUsed { get; set; }
       
        public static void SetLastUsed(this ITDengineClient client)
        {
            LastUsed = DateTime.UtcNow;
           
        }
        public static DateTime GetLastUsed(this ITDengineClient client)
        {
            return LastUsed;
        }
    }

}
